import { createLogger, format, transports } from 'winston'
import path from 'path'
import { promises as fs } from 'fs'
import dayjs from 'dayjs'
import { LoggerWrapper } from '@/log/wrapper'

export class ConnectLogger extends LoggerWrapper {
  private static cleanupOldLogsIsRunning = false
  private maxLogFiles = 1000 // 最多保存日志文件的份数
  private maxDays = 14 // 最多保存日志文件的天数

  readonly logFilePath: string // 日志文件路径
  readonly logDirectory: string // 日志文件夹路径

  constructor(
    logDirectory: string,
    connectId: string,
    options: {
      maxLogFiles?: number
      maxDays?: number
    } = {}
  ) {
    const timestamp = dayjs().format('YYYY-MM-DD-HH-mm-ss-SSS')
    const logFileName = `${timestamp}-${connectId}.log`
    const logFilePath = path.join(logDirectory, logFileName)

    const logger = createLogger({
      level: 'info',
      format: format.combine(
        format.timestamp({
          format: 'YYYY-MM-DD HH:mm:ss.SSS'
        }),
        LoggerWrapper.createFormatPrintf()
      ),
      transports: [new transports.File({ filename: logFilePath })]
    })

    super(logger)

    this.logDirectory = logDirectory
    this.logFilePath = logFilePath

    if (options.maxLogFiles && options.maxLogFiles > 0) {
      this.maxLogFiles = options.maxLogFiles
    }

    if (options.maxDays && options.maxDays > 0) {
      this.maxDays = options.maxDays
    }

    this.cleanupOldLogs()
  }

  public destroy() {
    this.logger.destroy()
  }

  private async cleanupOldLogs() {
    // 防止同时运行多个清理任务
    if (ConnectLogger.cleanupOldLogsIsRunning) return
    ConnectLogger.cleanupOldLogsIsRunning = true
    try {
      const files = await fs.readdir(this.logDirectory)
      const fileStats = await Promise.all(
        files.map(async (file) => {
          const filePath = path.join(this.logDirectory, file)
          const stats = await fs.stat(filePath)
          return { name: file, time: stats.mtime.getTime() }
        })
      )

      fileStats.sort((a, b) => b.time - a.time)

      const now = Date.now()
      const maxTime = this.maxDays * 24 * 60 * 60 * 1000

      const filesToDelete = fileStats.slice(this.maxLogFiles)

      fileStats.forEach((file) => {
        if (now - file.time > maxTime) {
          filesToDelete.push(file)
        }
      })

      await Promise.all(
        filesToDelete.map((file) => fs.unlink(path.join(this.logDirectory, file.name)))
      )
    } catch (err) {
      console.error(`Error cleaning up old logs: ${err}`)
    } finally {
      ConnectLogger.cleanupOldLogsIsRunning = false
    }
  }
}
